/*
 * Copyright (c) 2024 Huawei Technologies Co.,Ltd.
 *
 * openGauss is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 * http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * -------------------------------------------------------------------------
 *
 * htap_statistics.cpp
 * HTAP delta statistics provider.
 *
 * IDENTIFICATION
 * src/gausskernel/storage/htap/htap_statistics.cpp
 *
 * -------------------------------------------------------------------------
 */

#include "htap_statistics.h"
#include "config_manager.h"
#include "statistics_manager.h"
#include "htap_logger.h"
#include "htap_infra.h"
#include "htap_debug.h"
#include "mm_api.h"

namespace htap {
HTAP_DECLARE_LOGGER(HTAPDeltaStatistics, HTAP)

DeltaThreadStatistics::DeltaThreadStatistics(uint64_t threadId, void *inplaceBuffer)
    : MOT::ThreadStatistics(threadId, inplaceBuffer),
      m_absentUpdate(MakeName("delta-absent-updates", threadId).c_str()),
      m_presentUpdate(MakeName("delta-present-updates", threadId).c_str()),
      m_absentDelete(MakeName("delta-absent-deletes", threadId).c_str()),
      m_presentDelete(MakeName("delta-present-deletes", threadId).c_str())
{
    // register all statistic variables
    RegisterStatistics(&m_absentUpdate);
    RegisterStatistics(&m_presentUpdate);
    RegisterStatistics(&m_absentDelete);
    RegisterStatistics(&m_presentDelete);
}

MOT::TypedStatisticsGenerator<DeltaThreadStatistics, MOT::EmptyGlobalStatistics> DeltaStatisticsProvider::m_generator;
DeltaStatisticsProvider *DeltaStatisticsProvider::m_provider = nullptr;

DeltaStatisticsProvider::DeltaStatisticsProvider()
    : MOT::StatisticsProvider("HTAP Delta", &m_generator, HTAPInfra::GetInstance()->GetCfg().m_enableDeltaStatistics)
{}

DeltaStatisticsProvider::~DeltaStatisticsProvider()
{
    (void)MOT::ConfigManager::GetInstance().RemoveConfigChangeListener(this);
    if (m_enable) {
        (void)MOT::StatisticsManager::GetInstance().UnregisterStatisticsProvider(this);
    }
}

void DeltaStatisticsProvider::RegisterProvider()
{
    if (m_enable) {
        (void)MOT::StatisticsManager::GetInstance().RegisterStatisticsProvider(this);
    }
    (void)MOT::ConfigManager::GetInstance().AddConfigChangeListener(this);
}

bool DeltaStatisticsProvider::CreateInstance()
{
    bool result = false;
    HTAP_ASSERT(m_provider == nullptr);
    if (m_provider == nullptr) {
        m_provider = new (std::nothrow) DeltaStatisticsProvider();
        if (!m_provider) {
            HTAP_REPORT_ERROR(HTAP_ERROR_OOM, "Load Statistics",
                "Failed to allocate memory for HTAP Delta Statistics Provider, aborting");
        } else {
            result = m_provider->Initialize();
            if (!result) {
                HTAP_REPORT_ERROR(HTAP_ERROR_INTERNAL, "Load Statistics",
                    "Failed to initialize HTAP Delta Statistics Provider, aborting");
                delete m_provider;
                m_provider = nullptr;
            } else {
                m_provider->RegisterProvider();
                if (HTAPInfra::GetInstance()->GetCfg().m_enableDeltaStatistics) {
                    HTAP_LOG_INFO("HTAP delta statistics collection is enabled");
                } else {
                    HTAP_LOG_INFO("HTAP delta statistics collection is disabled");
                }
            }
        }
    }
    return result;
}

void DeltaStatisticsProvider::DestroyInstance()
{
    HTAP_ASSERT(m_provider != nullptr);
    if (m_provider != nullptr) {
        delete m_provider;
        m_provider = nullptr;
    }
}

DeltaStatisticsProvider &DeltaStatisticsProvider::GetInstance()
{
    HTAP_ASSERT(m_provider != nullptr);
    return *m_provider;
}

void DeltaStatisticsProvider::OnConfigChange()
{
    if (m_enable != HTAPInfra::GetInstance()->GetCfg().m_enableDeltaStatistics) {
        m_enable = HTAPInfra::GetInstance()->GetCfg().m_enableDeltaStatistics;
        if (m_enable) {
            (void)MOT::StatisticsManager::GetInstance().RegisterStatisticsProvider(this);
        } else {
            (void)MOT::StatisticsManager::GetInstance().UnregisterStatisticsProvider(this);
        }
    }
}

void DeltaStatisticsProvider::PrintStatisticsEx()
{
    MOT::MemPrint("Periodic Status", MOT::LogLevel::LL_INFO, MOT::MEM_REPORT_SUMMARY);
}

ModifyThreadStatistics::ModifyThreadStatistics(uint64_t threadId, void *inplaceBuffer)
    : MOT::ThreadStatistics(threadId, inplaceBuffer),
      m_insertRowModifyTime(MakeName("insert-row-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_updateRowModifyTime(MakeName("update-row-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_deleteRowModifyTime(MakeName("delete-row-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_commitTxnModifyTime(MakeName("commit-txn-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_abortTxnModifyTime(MakeName("abort-txn-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_commitSubTxnModifyTime(MakeName("commit-sub-txn-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_abortSubTxnModifyTime(MakeName("abort-sub-txn-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_emptyInsertRowModifyTime(MakeName("empty-insert-row-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_emptyUpdateRowModifyTime(MakeName("empty-update-row-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_emptyDeleteRowModifyTime(MakeName("empty-delete-row-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_emptyCommitTxnModifyTime(MakeName("empty-commit-txn-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_emptyAbortTxnModifyTime(MakeName("empty-abort-txn-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_emptyCommitSubTxnModifyTime(MakeName("empty-commit-sub-txn-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_emptyAbortSubTxnModifyTime(MakeName("empty-abort-sub-txn-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_errorInsertRowModifyTime(MakeName("error-insert-row-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_errorUpdateRowModifyTime(MakeName("error-update-row-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_errorDeleteRowModifyTime(MakeName("error-delete-row-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_errorCommitTxnModifyTime(MakeName("error-commit-txn-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_errorAbortTxnModifyTime(MakeName("error-abort-txn-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_errorCommitSubTxnModifyTime(MakeName("error-commit-sub-txn-modify-time", threadId).c_str(), 1, "micro-seconds"),
      m_errorAbortSubTxnModifyTime(MakeName("error-abort-sub-txn-modify-time", threadId).c_str(), 1, "micro-seconds")
{
    // register all statistic variables
    RegisterStatistics(&m_insertRowModifyTime);
    RegisterStatistics(&m_updateRowModifyTime);
    RegisterStatistics(&m_deleteRowModifyTime);
    RegisterStatistics(&m_commitTxnModifyTime);
    RegisterStatistics(&m_abortTxnModifyTime);
    RegisterStatistics(&m_commitSubTxnModifyTime);
    RegisterStatistics(&m_abortSubTxnModifyTime);
    RegisterStatistics(&m_emptyInsertRowModifyTime);
    RegisterStatistics(&m_emptyUpdateRowModifyTime);
    RegisterStatistics(&m_emptyDeleteRowModifyTime);
    RegisterStatistics(&m_emptyCommitTxnModifyTime);
    RegisterStatistics(&m_emptyAbortTxnModifyTime);
    RegisterStatistics(&m_emptyCommitSubTxnModifyTime);
    RegisterStatistics(&m_emptyAbortSubTxnModifyTime);
    RegisterStatistics(&m_errorInsertRowModifyTime);
    RegisterStatistics(&m_errorUpdateRowModifyTime);
    RegisterStatistics(&m_errorDeleteRowModifyTime);
    RegisterStatistics(&m_errorCommitTxnModifyTime);
    RegisterStatistics(&m_errorAbortTxnModifyTime);
    RegisterStatistics(&m_errorCommitSubTxnModifyTime);
    RegisterStatistics(&m_errorAbortSubTxnModifyTime);
}

MOT::TypedStatisticsGenerator<ModifyThreadStatistics, MOT::EmptyGlobalStatistics> ModifyStatisticsProvider::m_generator;
ModifyStatisticsProvider *ModifyStatisticsProvider::m_provider = nullptr;

ModifyStatisticsProvider::ModifyStatisticsProvider()
    : MOT::StatisticsProvider("HTAP Modifys", &m_generator, HTAPInfra::GetInstance()->GetCfg().m_enableModifyStatistics)
{}

ModifyStatisticsProvider::~ModifyStatisticsProvider()
{
    (void)MOT::ConfigManager::GetInstance().RemoveConfigChangeListener(this);
    if (m_enable) {
        (void)MOT::StatisticsManager::GetInstance().UnregisterStatisticsProvider(this);
    }
}

void ModifyStatisticsProvider::RegisterProvider()
{
    if (m_enable) {
        (void)MOT::StatisticsManager::GetInstance().RegisterStatisticsProvider(this);
    }
    (void)MOT::ConfigManager::GetInstance().AddConfigChangeListener(this);
}

bool ModifyStatisticsProvider::CreateInstance()
{
    bool result = false;
    HTAP_ASSERT(m_provider == nullptr);
    if (m_provider == nullptr) {
        m_provider = new (std::nothrow) ModifyStatisticsProvider();
        if (!m_provider) {
            HTAP_REPORT_ERROR(HTAP_ERROR_OOM, "Load Statistics",
                              "Failed to allocate memory for HTAP Modify Statistics Provider, aborting");
        } else {
            result = m_provider->Initialize();
            if (!result) {
                HTAP_REPORT_ERROR(HTAP_ERROR_INTERNAL, "Load Statistics",
                                  "Failed to initialize HTAP Modify Statistics Provider, aborting");
                delete m_provider;
                m_provider = nullptr;
            } else {
                m_provider->RegisterProvider();
                if (HTAPInfra::GetInstance()->GetCfg().m_enableModifyStatistics) {
                    HTAP_LOG_INFO("HTAP Modify statistics collection is enabled");
                } else {
                    HTAP_LOG_INFO("HTAP Modify statistics collection is disabled");
                }
            }
        }
    }
    return result;
}

void ModifyStatisticsProvider::DestroyInstance()
{
    HTAP_ASSERT(m_provider != nullptr);
    if (m_provider != nullptr) {
        delete m_provider;
        m_provider = nullptr;
    }
}

ModifyStatisticsProvider &ModifyStatisticsProvider::GetInstance()
{
    HTAP_ASSERT(m_provider != nullptr);
    return *m_provider;
}

void ModifyStatisticsProvider::OnConfigChange()
{
    if (m_enable != HTAPInfra::GetInstance()->GetCfg().m_enableModifyStatistics) {
        m_enable = HTAPInfra::GetInstance()->GetCfg().m_enableModifyStatistics;
        if (m_enable) {
            (void)MOT::StatisticsManager::GetInstance().RegisterStatisticsProvider(this);
        } else {
            (void)MOT::StatisticsManager::GetInstance().UnregisterStatisticsProvider(this);
        }
    }
}

void ModifyStatisticsProvider::PrintStatisticsEx()
{
    MOT::MemPrint("Periodic Status", MOT::LogLevel::LL_INFO, MOT::MEM_REPORT_SUMMARY);
}

FlushThreadStatistics::FlushThreadStatistics(uint64_t threadId, void *inplaceBuffer)
    : MOT::ThreadStatistics(threadId, inplaceBuffer),
      m_permanentFlushTime(MakeName("permanent-flush-time", threadId).c_str(), 1, "micro-seconds"),
      m_addingNewRows(MakeName("flush-adding-to-new-rows", threadId).c_str()),
      m_deleteRows(MakeName("flush-delete-rows", threadId).c_str()),
      m_numRG(MakeName("flush-num-rg", threadId).c_str()),
      m_numDeleteCall(MakeName("flush-call-handle-delete", threadId).c_str())

{
    // register all statistic variables
    RegisterStatistics(&m_permanentFlushTime);
    RegisterStatistics(&m_addingNewRows);
    RegisterStatistics(&m_deleteRows);
    RegisterStatistics(&m_numRG);
    RegisterStatistics(&m_numDeleteCall);
}

MOT::TypedStatisticsGenerator<FlushThreadStatistics, MOT::EmptyGlobalStatistics> FlushStatisticsProvider::m_generator;
FlushStatisticsProvider *FlushStatisticsProvider::m_provider = nullptr;

FlushStatisticsProvider::FlushStatisticsProvider()
    : MOT::StatisticsProvider("HTAP FLUSH", &m_generator, HTAPInfra::GetInstance()->GetCfg().m_enableFlushStatistics)
{}

FlushStatisticsProvider::~FlushStatisticsProvider()
{
    (void)MOT::ConfigManager::GetInstance().RemoveConfigChangeListener(this);
    if (m_enable) {
        (void)MOT::StatisticsManager::GetInstance().UnregisterStatisticsProvider(this);
    }
}

void FlushStatisticsProvider::RegisterProvider()
{
    if (m_enable) {
        (void)MOT::StatisticsManager::GetInstance().RegisterStatisticsProvider(this);
    }
    (void)MOT::ConfigManager::GetInstance().AddConfigChangeListener(this);
}

bool FlushStatisticsProvider::CreateInstance()
{
    bool result = false;
    HTAP_ASSERT(m_provider == nullptr);
    if (m_provider == nullptr) {
        m_provider = new (std::nothrow) FlushStatisticsProvider();
        if (!m_provider) {
            HTAP_REPORT_ERROR(HTAP_ERROR_OOM, "Load Statistics",
                              "Failed to allocate memory for HTAP FLUSH Statistics Provider, aborting");
        } else {
            result = m_provider->Initialize();
            if (!result) {
                HTAP_REPORT_ERROR(HTAP_ERROR_INTERNAL, "Load Statistics",
                                  "Failed to initialize HTAP FLUSH Statistics Provider, aborting");
                delete m_provider;
                m_provider = nullptr;
            } else {
                m_provider->RegisterProvider();
                if (HTAPInfra::GetInstance()->GetCfg().m_enableFlushStatistics) {
                    HTAP_LOG_INFO("HTAP flush statistics collection is enabled");
                } else {
                    HTAP_LOG_INFO("HTAP flush statistics collection is disabled");
                }
            }
        }
    }
    return result;
}

void FlushStatisticsProvider::DestroyInstance()
{
    HTAP_ASSERT(m_provider != nullptr);
    if (m_provider != nullptr) {
        delete m_provider;
        m_provider = nullptr;
    }
}

FlushStatisticsProvider &FlushStatisticsProvider::GetInstance()
{
    HTAP_ASSERT(m_provider != nullptr);
    return *m_provider;
}

void FlushStatisticsProvider::OnConfigChange()
{
    if (m_enable != HTAPInfra::GetInstance()->GetCfg().m_enableFlushStatistics) {
        m_enable = HTAPInfra::GetInstance()->GetCfg().m_enableFlushStatistics;
        if (m_enable) {
            (void)MOT::StatisticsManager::GetInstance().RegisterStatisticsProvider(this);
        } else {
            (void)MOT::StatisticsManager::GetInstance().UnregisterStatisticsProvider(this);
        }
    }
}

void FlushStatisticsProvider::PrintStatisticsEx()
{
    MOT::MemPrint("Periodic Status", MOT::LogLevel::LL_INFO, MOT::MEM_REPORT_SUMMARY);
}
} // namespace htap
